#include <linux/init.h>
#include <linux/kallsyms.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/uaccess.h>

static int tpi = 0;
module_param(tpi, int, 0644);
static char* tpc = "hahaha";
module_param(tpc, charp, 0644);

// tpi setter callback
int my_param_set_int(const char* val, const struct kernel_param* kp)
{
    int* pvalue = kp->arg;  // Pointer to actual parameter variable.
    int  res    = param_set_int(val, kp);  // Use helper for write variable
    if (res == 0) {
        // Here you may execute additional actions when you write parameter.
        printk("int set param %d\n", *pvalue);
    }
    return res;
}
// tpi getter callback
int my_param_get_int(char* buffer, const struct kernel_param* kp)
{
    // int* pvalue = kp->arg; // Pointer to actual parameter variable.
    int res = param_get_int(buffer, kp);  // Use helper for write variable
    printk("int getter talks \n");
    return res;
}

// tpi param ops
const struct kernel_param_ops my_param_ops_int = {
    .set = &my_param_set_int,  // Use our setter ...
    .get = &my_param_get_int,  // .. and standard getter
};

module_param_cb(my_int,            /*filename*/
                &my_param_ops_int, /*operations*/
                &tpi, /* pointer to variable, contained parameter's value */
                0644  /*permissions on file*/
);

// tpc setter callback
int my_param_set_string(const char* val, const struct kernel_param* kp)
{
    char* pvalue = kp->arg;  // Pointer to actual parameter variable.
    int   res    = param_set_charp(val, kp);  // Use helper for write variable
    if (res == 0) {
        // Here you may execute additional actions when you write parameter.
        printk("string set param %s\n", pvalue);
    }
    return res;
}
// tpc getter callback
int my_param_get_string(char* buffer, const struct kernel_param* kp)
{
    // int* pvalue = kp->arg; // Pointer to actual parameter variable.
    int res = param_get_charp(buffer, kp);  // Use helper for write variable
    printk("string getter talks \n");
    return res;
}

// tpc param ops
const struct kernel_param_ops my_param_ops_string = {
    .set = &my_param_set_string,  // Use our setter ...
    .get = &my_param_get_string,  // .. and standard getter
};

module_param_cb(my_string,            /*filename*/
                &my_param_ops_string, /*operations*/
                &tpc, /* pointer to variable, contained parameter's value */
                0644  /*permissions on file*/
);

static int proc_init(void)
{
    printk("param-test init \n");
    return 0;
}

static void proc_cleanup(void) { printk("param-test uninstall \n"); }

module_init(proc_init);
module_exit(proc_cleanup);
MODULE_LICENSE("GPL");